package lelouet.datacenter.simulation.factorized;

import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.List;

import lelouet.datacenter.simulation.Event;

public abstract class WorkingElementImpl implements WorkingElement {

	public WorkingElementImpl(String id, long time) {
		this.id = id;
		this.time = time;
	}

	private final String id;

	@Override
	public String getId() {
		return id;
	}

	protected long time;

	@Override
	public long getTime() {
		return time;
	}

	@Override
	public int hashCode() {
		return getId().hashCode();
	}

	@Override
	public boolean equals(Object o) {
		if (o == this) {
			return true;
		}
		if (o == null) {
			return false;
		}
		if (o instanceof WorkingElement) {
			return id.equals(((WorkingElement) o).getId());
		}
		return false;
	}

	/**
	 * the list of last triggered events, that must be triggered at once on next
	 * work.
	 */
	private List<Event> triggeredEvents = new ArrayList<Event>();

	/**
	 * The list of events triggered while processing the previous triggered
	 * ones. That allows to iterate over {@link #triggeredEvents} while some
	 * events are added
	 */
	private List<Event> triggeredEventsBackBuffer = new ArrayList<Event>();

	/**
	 * place a event, that should have been triggered on this time slot, in a
	 * list of triggered events. there are two lists, a front one that receive
	 * incoming events, and a back one that is to be read to prevent
	 * {@link ConcurrentModificationException}s
	 * 
	 * @see #getTriggeredEvents()
	 * @see #hasNewTriggeredEvents()
	 */
	protected void addTriggeredEvent(Event event) {
		triggeredEvents.add(event);
	}

	/**
	 * swaps the two lists of triggered events, clears the top one now and
	 * return the back one.
	 * 
	 * @see #addTriggeredEvent(Event)
	 * @see #hasNewTriggeredEvents()
	 */
	protected List<Event> getTriggeredEvents() {
		List<Event> tmplist = triggeredEvents;
		triggeredEvents = triggeredEventsBackBuffer;
		triggeredEventsBackBuffer = tmplist;
		triggeredEvents.clear();
		return triggeredEventsBackBuffer;
	}

	/**
	 * @return true if the front (receiving) list contains events, that is, if
	 *         events have been triggered since last
	 *         {@link #getTriggeredEvents()}
	 * 
	 * @see #getTriggeredEvents()
	 * @see #addTriggeredEvent(Event)
	 */
	protected boolean hasNewTriggeredEvents() {
		return !triggeredEvents.isEmpty();
	}

}
